﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;
using YJKFloor.Forms;
using YJKFloor.InclineFloor;
using YJKFloor.Utility;

namespace YJKFloor.FloorEditor
{
	public class FloorInclineEditor
	{
		public FloorInclineEditor(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
			this.m_EditCommon = new FloorEditCommon(cmdData);
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Incline(ref string msg)
		{
			InclineFloorForm inclineFloorForm = new InclineFloorForm();
			inclineFloorForm.Show(CmdInclineFloor._hWndRevit);
			int wMsg = 7;
			FloorInclineEditor.SendMessage(CmdInclineFloor._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Result result2;
			try
			{
				for (;;)
				{
					Floor floor = null;
					Result result = this.SelectFloor(ref floor);
                    if (result != Result.Failed)
					{
						if (result == Autodesk.Revit.UI.Result.Cancelled)
						{
							break;
						}
						List<XYZ> vertexes = new List<XYZ>();
						if (!this.GetFloorVertexLoop(floor, ref vertexes))
						{
							MessageBox.Show("选择的不是水平楼板", "盈建科提示");
						}
						else
						{
							Line edge = null;
							result = this.SelectEdge(floor, ref edge);
							if (result == Autodesk.Revit.UI.Result.Cancelled)
							{
								break;
							}
							if (result != Result.Failed)
							{
								if (inclineFloorForm.IsSelEdgeIncline)
								{
									this.SelEdgeIncline(floor, vertexes, edge, inclineFloorForm.ZOffset);
								}
								else
								{
									this.RotationByEdge(floor, vertexes, edge, inclineFloorForm.RotateAngle);
								}
								MessageBox.Show("楼板修改成功。", "盈建科提示");
							}
						}
					}
				}
				inclineFloorForm.Close();
				result2 = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				inclineFloorForm.Close();
				result2 = Autodesk.Revit.UI.Result.Failed;
			}
			return result2;
		}

		private Result SelectFloor(ref Floor floor)
		{
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				Reference reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new FloorFilter(), "选择一块楼板");
				floor = (this.m_Doc.GetElement(reference) as Floor);
				if (floor == null)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SelectEdge(Floor selectedFloor, ref Line edge)
		{
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			Result result;
			try
			{
				Reference reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Edge, "选择楼板的直线边界");
				Element element = this.m_Revit.Application.ActiveUIDocument.Document.GetElement(reference);
				Edge edge2 = element.GetGeometryObjectFromReference(reference) as Edge;
				Floor floor = element as Floor;
				if (floor.Id.IntegerValue != selectedFloor.Id.IntegerValue)
				{
					MessageBox.Show("选择的边界不属于当前楼板", "盈建科提示");
					result = Autodesk.Revit.UI.Result.Failed;
				}
				else
				{
					Curve curve = edge2.AsCurve();
					if (curve.GetType() != typeof(Line))
					{
						MessageBox.Show("选择的边界不是直线的", "盈建科提示");
						result = Autodesk.Revit.UI.Result.Failed;
					}
					else
					{
						edge = (curve as Line);
						result = Autodesk.Revit.UI.Result.Succeeded;
					}
				}
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Cancelled;
			}
			return result;
		}

		private void SelEdgeIncline(Floor floor, List<XYZ> vertexes, Line edge, double zOffset)
		{
			XYZ xyz = edge.GetEndPoint(0);
			XYZ xyz2 = edge.GetEndPoint(1);
			XYZ faceVertex = null;
			double val = 0.0;
			foreach (XYZ xyz3 in vertexes)
			{
				if (!xyz3.IsAlmostEqualTo(xyz) && !xyz3.IsAlmostEqualTo(xyz2))
				{
					XYZ pt = Geometry.CalculateFootPoint(xyz, xyz2, xyz3);
					double num = this.To2d(pt).DistanceTo(this.To2d(xyz3));
					if (Geometry.LessThan(val, num))
					{
						val = num;
						faceVertex = xyz3;
					}
				}
			}
			xyz += XYZ.BasisZ * zOffset;
			xyz2 += XYZ.BasisZ * zOffset;
			SlabShapeEditor slabShapeEditor = floor.SlabShapeEditor;
			if (slabShapeEditor == null)
			{
				return;
			}
			Transaction transaction = new Transaction(this.m_Doc);
			transaction.Start("EditVertex");
			XYZ xyz4 = XYZ.BasisZ * zOffset;
			try
			{
				foreach (XYZ xyz5 in vertexes)
				{
					XYZ xyz6 = null;
					if (Geometry.IntersectLineToPlanerFace(xyz5, xyz5 + xyz4, xyz, xyz2, faceVertex, ref xyz6))
					{
						slabShapeEditor.DrawPoint(xyz6);
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				transaction.RollBack();
			}
		}

		private void RotationByEdge(Floor floor, List<XYZ> vertexes, Line edge, double angle)
		{
			XYZ hyendPoint = edge.GetEndPoint(0);
			XYZ hyendPoint2 = edge.GetEndPoint(1);
			XYZ xyz = null;
			double num = 0.0;
			foreach (XYZ xyz2 in vertexes)
			{
				if (!xyz2.IsAlmostEqualTo(hyendPoint) && !xyz2.IsAlmostEqualTo(hyendPoint2))
				{
					XYZ pt = Geometry.CalculateFootPoint(hyendPoint, hyendPoint2, xyz2);
					double num2 = this.To2d(pt).DistanceTo(this.To2d(xyz2));
					if (Geometry.LessThan(num, num2))
					{
						num = num2;
						xyz = xyz2;
					}
				}
			}
			double num3 = num * Math.Tan(angle);
			xyz += XYZ.BasisZ * num3;
			SlabShapeEditor slabShapeEditor = floor.SlabShapeEditor;
			if (slabShapeEditor == null)
			{
				return;
			}
			Transaction transaction = new Transaction(this.m_Doc);
			transaction.Start("EditVertex");
			XYZ xyz3 = XYZ.BasisZ * num3;
			try
			{
				foreach (XYZ xyz4 in vertexes)
				{
					XYZ xyz5 = null;
					if (Geometry.IntersectLineToPlanerFace(xyz4, xyz4 + xyz3, hyendPoint, hyendPoint2, xyz, ref xyz5))
					{
						slabShapeEditor.DrawPoint(xyz5);
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				transaction.RollBack();
			}
		}

		private XYZ To2d(XYZ pt)
		{
			return new XYZ(pt.X, pt.Y, 0.0);
		}

		private bool GetFloorVertexLoop(Floor floor, ref List<XYZ> vertexes)
		{
			List<List<Curve>> list = new List<List<Curve>>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			this.m_EditCommon.GetFloorLoopAndOpeningLoop(floor, ref list, ref list2);
			if (list.Count == 0)
			{
				return false;
			}
			if (list[0].Count == 0)
			{
				return false;
			}
			double floorElevation = this.GetFloorElevation(floor);
			foreach (Curve curve in list[0])
			{
				XYZ xyz = curve.GetEndPoint(0);
				xyz = new XYZ(xyz.X, xyz.Y, floorElevation);
				vertexes.Add(xyz);
			}
			return true;
		}

		private double GetFloorElevation(Floor floor)
		{
			double num = 0.0;
			double result;
			try
			{
				ElementId elementId = floor.GetParameter(BuiltInParameter.SCHEDULE_LEVEL_PARAM).AsElementId();
				Level level = this.m_Doc.GetElement(elementId) as Level;
				num = level.Elevation;
				double num2 = floor.GetParameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).AsDouble();
				num += num2;
				result = num;
			}
			catch (Exception)
			{
				result = num;
			}
			return result;
		}

		private ExternalCommandData m_Revit;

		private Document m_Doc;

		private FloorEditCommon m_EditCommon;
	}
}
